#region Using References

using System;
using System.Diagnostics.Contracts;

#endregion

namespace Beaker.OpenCube.Game
{
	// [Pure]
	public struct Coordinates2<T>
		: IEquatable<Coordinates2<T>>
		where T : struct, IEquatable<T>
	{
		public static readonly Coordinates2<T> Empty = new Coordinates2<T>( default( T ), default( T ) );

		public Coordinates2( T x, T z )
		{
			Contract.Ensures( x.Equals( Contract.ValueAtReturn( out _x ) ) );
			Contract.Ensures( z.Equals( Contract.ValueAtReturn( out _z ) ) );

			_x = x;
			_z = z;
		}

		private readonly T _x;

		/// <summary>
		/// Gets the X coordinate
		/// </summary>
		[Pure]
		public T X
		{
			get
			{
				Contract.Ensures( Contract.Result<T>().Equals( _x ) );
				return _x;
			}
		}

		private readonly T _z;

		/// <summary>
		/// Gets the Z coordinate
		/// </summary>
		[Pure]
		public T Z
		{
			get
			{
				Contract.Ensures( Contract.Result<T>().Equals( _z ) );
				return _z;
			}
		}

		/// <summary>
		/// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
		/// </summary>
		/// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
		/// <returns>
		///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
		/// </returns>
		[Pure]
		public override bool Equals( object obj )
		{
			if( ReferenceEquals( null, obj ) ) return false;
			return obj is Coordinates2<T> && Equals( (Coordinates2<T>)obj );
		}

		/// <summary>
		/// Determines whether the specified coordinates are equal to this instance.
		/// </summary>
		/// <param name="other">The coordinates to compare with this instance.</param>
		/// <returns>
		///   <c>true</c> if the specified coordinates are equal to this instance; otherwise, <c>false</c>.
		/// </returns>
		[Pure]
		public bool Equals( Coordinates2<T> other )
		{
			Contract.Ensures( Contract.Result<bool>() == false || ( _x.Equals( other._x ) && _z.Equals( other._z ) ) );
			return _x.Equals( other._x ) && _z.Equals( other._z );
		}

		/// <summary>
		/// Returns a hash code for this instance.
		/// </summary>
		/// <returns>
		/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
		/// </returns>
		[Pure]
		public override int GetHashCode()
		{
			unchecked
			{
				int hashCode = _x.GetHashCode();
				hashCode = ( hashCode * 397 ) ^ _z.GetHashCode();
				return hashCode;
			}
		}

		public static bool operator ==( Coordinates2<T> left, Coordinates2<T> right )
		{
			return left.Equals( right );
		}

		public static bool operator !=( Coordinates2<T> left, Coordinates2<T> right )
		{
			return !left.Equals( right );
		}
	}
}